001 /*
002 * Copyright 2005 Stephen J. McConnell.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.library;
020
021 import java.io.File;
022
023 import net.dpml.lang.Version;
024 import net.dpml.lang.Enum;
025
026 import net.dpml.transit.Artifact;
027
028 /**
029 * Enumeration identifying resource features.
030 *
031 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
032 * @version 1.1.0
033 */
034 public final class Feature extends Enum
035 {
036 static final long serialVersionUID = 1L;
037
038 /**
039 * Resource name.
040 */
041 public static final Feature NAME = new Feature( "name" );
042
043 /**
044 * Resource group.
045 */
046 public static final Feature GROUP = new Feature( "group" );
047
048 /**
049 * Resource version.
050 */
051 public static final Feature VERSION = new Feature( "version" );
052
053 /**
054 * Resource decimal version.
055 */
056 public static final Feature DECIMAL = new Feature( "decimal" );
057
058 /**
059 * Resource version.
060 */
061 public static final Feature URI = new Feature( "uri" );
062
063 /**
064 * Resource spec.
065 */
066 public static final Feature SPEC = new Feature( "spec" );
067
068 /**
069 * Resource path.
070 */
071 public static final Feature PATH = new Feature( "path" );
072
073 /**
074 * Resource filename.
075 */
076 public static final Feature FILENAME = new Feature( "filename" );
077
078 /**
079 * Project basedir.
080 */
081 public static final Feature BASEDIR = new Feature( "basedir" );
082
083 /**
084 * Array of scope enumeration values.
085 */
086 private static final Feature[] ENUM_VALUES =
087 new Feature[]{NAME, GROUP, VERSION, DECIMAL, URI, SPEC, PATH, FILENAME, BASEDIR};
088
089 /**
090 * Returns an array of activation enum values.
091 * @return the activation policies array
092 */
093 public static Feature[] values()
094 {
095 return ENUM_VALUES;
096 }
097
098 /**
099 * Internal constructor.
100 * @param label the enumeration label.
101 * @param index the enumeration index.
102 */
103 private Feature( String label )
104 {
105 super( label );
106 }
107
108 /**
109 * Return a string representation of the scope.
110 * @return the string value
111 */
112 public String toString()
113 {
114 return getName().toUpperCase();
115 }
116
117 /**
118 * Return a feature.
119 * @param value the feature name
120 * @return the feature
121 * @exception IllegalArgumentException if the name if not a recognized feature.
122 */
123 public static Feature parse( String value ) throws IllegalArgumentException
124 {
125 if( value.equalsIgnoreCase( "name" ) )
126 {
127 return NAME;
128 }
129 else if( value.equalsIgnoreCase( "group" ) )
130 {
131 return GROUP;
132 }
133 else if( value.equalsIgnoreCase( "version" ) )
134 {
135 return VERSION;
136 }
137 else if( value.equalsIgnoreCase( "decimal" ) )
138 {
139 return DECIMAL;
140 }
141 else if( value.equalsIgnoreCase( "uri" ) )
142 {
143 return URI;
144 }
145 else if( value.equalsIgnoreCase( "spec" ) )
146 {
147 return SPEC;
148 }
149 else if( value.equalsIgnoreCase( "path" ) )
150 {
151 return PATH;
152 }
153 else if( value.equalsIgnoreCase( "filename" ) )
154 {
155 return FILENAME;
156 }
157 else if( value.equalsIgnoreCase( "basedir" ) )
158 {
159 return BASEDIR;
160 }
161 else
162 {
163 final String error =
164 "Unrecognized feature argument [" + value + "]";
165 throw new IllegalArgumentException( error );
166 }
167 }
168
169 /**
170 * Return the value of a feature.
171 * @param resource the target resource
172 * @param feature the feature
173 * @return the resolved value
174 */
175 public static String resolve( Resource resource, Feature feature )
176 {
177 return resolve( resource, feature, null, false );
178 }
179
180 /**
181 * Return the value of a feature.
182 * @param resource the target resource
183 * @param feature the feature
184 * @param type the selected type
185 * @return the resolved value
186 */
187 public static String resolve( Resource resource, Feature feature, Type type )
188 {
189 return resolve( resource, feature, type, false );
190 }
191
192 /**
193 * Return the value of a feature.
194 * @param resource the target resource
195 * @param feature the feature
196 * @param type the selected type
197 * @param alias flag indicated that alias based uri resolution is requested
198 * @return the resolved value
199 */
200 public static String resolve( Resource resource, Feature feature, Type type, boolean alias )
201 {
202 if( null != type && !resource.isa( type.getID() ) )
203 {
204 final String error =
205 "The feature request for the type ["
206 + type
207 + "] from the resource ["
208 + resource
209 + "] cannot be fullfilled because the resource does not declare "
210 + "production of the requested type.";
211 throw new FeatureRuntimeException( error );
212 }
213
214 if( feature.equals( Feature.NAME ) )
215 {
216 return resource.getName();
217 }
218 else if( feature.equals( Feature.GROUP ) )
219 {
220 return resource.getParent().getResourcePath();
221 }
222 else if( feature.equals( Feature.VERSION ) )
223 {
224 String version = resource.getVersion();
225 if( null == version )
226 {
227 return "";
228 }
229 else
230 {
231 return version;
232 }
233 }
234 else if( feature.equals( Feature.DECIMAL ) )
235 {
236 Version version = resource.getDecimalVersion();
237 if( null == version )
238 {
239 return "";
240 }
241 else
242 {
243 return version.toString();
244 }
245 }
246 else if( feature.equals( Feature.URI ) )
247 {
248 return resolveURIFeature( resource, type, alias );
249 }
250 else if( feature.equals( Feature.SPEC ) )
251 {
252 String path = resource.getResourcePath();
253 String version =resource.getVersion();
254 if( null == version )
255 {
256 return path;
257 }
258 else
259 {
260 return path + "#" + version;
261 }
262 }
263 else if( feature.equals( Feature.PATH ) )
264 {
265 if( null == type )
266 {
267 final String error =
268 "Type must be supplied in conjuction with the uri feature.";
269 throw new FeatureRuntimeException( error );
270 }
271 else
272 {
273 String id = type.getID();
274 Artifact artifact = resource.getArtifact( id );
275 try
276 {
277 File cached =
278 (File) artifact.toURL().getContent( new Class[]{File.class} );
279 return cached.getCanonicalPath();
280 }
281 catch( Exception e )
282 {
283 final String error =
284 "Unable to resolve resource path.";
285 throw new FeatureRuntimeException( error, e );
286 }
287 }
288 }
289 else if( feature.equals( Feature.FILENAME ) )
290 {
291 if( null == type )
292 {
293 final String error =
294 "Type must be supplied in conjuction with the filename feature.";
295 throw new IllegalArgumentException( error );
296 }
297 String id = type.getID();
298 return resource.getLayoutPath( id );
299 }
300 else if( feature.equals( Feature.BASEDIR ) )
301 {
302 File base = resource.getBaseDir();
303 if( null == base )
304 {
305 throw new IllegalArgumentException( "basedir" );
306 }
307 else
308 {
309 try
310 {
311 return base.getCanonicalPath();
312 }
313 catch( Exception e )
314 {
315 final String error =
316 "Unexpected error while resolving project basedir [" + base + "].";
317 throw new FeatureRuntimeException( error, e );
318 }
319 }
320 }
321 else
322 {
323 final String error =
324 "Invalid feature [" + feature + "].";
325 throw new FeatureRuntimeException( error );
326 }
327 }
328
329 private static String resolveURIFeature( Resource resource, Type type )
330 {
331 return resolveURIFeature( resource, type, false );
332 }
333
334 private static String resolveURIFeature( Resource resource, Type type, boolean alias )
335 {
336 if( null == type )
337 {
338 final String error =
339 "Type must be supplied in conjuction with the uri feature request.";
340 throw new FeatureRuntimeException( error );
341 }
342 else
343 {
344 String id = type.getID();
345 if( alias )
346 {
347 Version version = type.getVersion();
348 if( null != version )
349 {
350 Artifact artifact = resource.getArtifact( id );
351 String group = artifact.getGroup();
352 String name = artifact.getName();
353 if( Version.NULL_VERSION.equals( version ) )
354 {
355 return "link:"
356 + id
357 + ":"
358 + group
359 + "/"
360 + name;
361 }
362 else
363 {
364 int major = version.getMajor();
365 int minor = version.getMinor();
366 return "link:"
367 + id
368 + ":"
369 + group
370 + "/"
371 + name
372 + "#"
373 + major
374 + "."
375 + minor;
376 }
377 }
378 else
379 {
380 final String error =
381 "Cannot resolve link from resource ["
382 + resource
383 + "] because the resource does not declare production of an alias for the type ["
384 + id
385 + "].";
386 throw new FeatureRuntimeException( error );
387 }
388 }
389 else
390 {
391 Artifact artifact = resource.getArtifact( id );
392 return artifact.toURI().toASCIIString();
393 }
394 }
395 }
396 }
397